let s = 'Hello world!';
s.startsWith('Hello') // true 
s.endsWith('!') // true
s.includes('o') // true  在不需要索引时使用includes代替indexof更方便

/*
这三个方法都支持第二个参数，表示开始搜索的位置。
使用第二个参数n时，endsWith的行为与其他两个方法有所不同。
它针对前n个字符，而其他两个方法针对从第n个位置直到字符串结束。
*/
let s = 'Hello world!';
s.startsWith('world', 6) // true 向后
s.endsWith('Hello', 5) // true 向前
s.includes('Hello', 6) // false 向后

/*
repeat方法返回一个新字符串，表示将原字符串重复n次。
*/
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // "" 注意0次是空
'na'.repeat(2.9) // "nana"  小数会被取整
'na'.repeat(Infinity) // RangeError  
'na'.repeat(-1) // RangeError  负数 和 无穷 会报错
'na'.repeat(-0.9) // ""   -0.9会被取整为0
'na'.repeat(NaN) // ""  参数NaN会被当做0。
//如果repeat的参数是字符串，则会先转换成数字。
'na'.repeat('na') // ""



/*
ES2017引入了字符串补全长度的功能。如果某个字符串不够指定长度，会在头部或尾部补全。
padStart()用于头部补全，padEnd()用于尾部补全。
padStart()和padEnd()一共接受两个参数，第一个参数是字符串补全生效的最大长度，第二个参数是用来补全的字符串。
*/

'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'   注意这里:abab 但只需要3位 所以截成aba

'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'

//如果原字符串的长度，等于或大于最大长度，则字符串补全不生效，返回原字符串。(不需要自己在判断了,优化很好)
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'

//如果省略第二个参数，默认使用空格补全长度。
'x'.padStart(4) // '   x'
'x'.padEnd(4) // 'x   '


//真实用途  补0   提示字符串格式

'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"


'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"

//消除空格
const s = '  abc  ';
s.trim() // "abc"
s.trimStart() // "abc  "
s.trimEnd() // "  abc"


/*

replaceAll()  注意:es2021才有的api 

第二个参数replacement是一个字符串，表示替换的文本，其中可以使用一些特殊字符串。

$& 匹配的子字符串。
$` 匹配结果前面的文本。
$' 匹配结果后面的文本。
$n 匹配成功的第n组内容，n是从1开始的自然数。这个参数生效的前提是，第一个参数必须是正则表达式。
$$ 指代美元符号$。

*/

'aabbcc'.replace(/b/, '_') // 不报错
'aabbcc'.replaceAll(/b/, '_') // 报错  必须加g



'abbc'.replaceAll('b', '$&') // $& 表示匹配的字符串，即`b`本身 所以返回结果与原字符串一致

// $` 表示匹配结果之前的字符串
// 对于第一个`b`，$` 指代`a`
// 对于第二个`b`，$` 指代`ab`
'abbc'.replaceAll('b', '$`') // 'aaabc'


// $' 表示匹配结果之后的字符串
// 对于第一个`b`，$' 指代`bc`
// 对于第二个`b`，$' 指代`c`
'abbc'.replaceAll('b', `$'`) // 'abccc'


// $1 表示正则表达式的第一个组匹配，指代`ab`
// $2 表示正则表达式的第二个组匹配，指代`bc`
'abbc'.replaceAll(/(ab)(bc)/g, '$2$1')
// 'bcab'

// $$ 指代 $
'abc'.replaceAll('b', '$$')
// 'a$c'



'aabbcc'.replaceAll('b', () => '_')
// 'aa__cc'  replacement也可以是函数


/*
这个替换函数可以接受多个参数。
第一个参数是捕捉到的匹配内容=>match
第二个参数捕捉到是组匹配（有多少个组匹配，就有多少个对应的参数）。
倒数第二个参数match在整个字符串中的位置，
最后一个参数是原字符串。
*/

const str = '123abc456';
const regex = /(\d+)([a-z]+)(\d+)/g;

function replacer(match, p1, p2, p3, offset, string) {
	return [p1, p2, p3].join(' - ');
}

str.replaceAll(regex, replacer)
// 123 - abc - 456
